﻿/*
 *  Sqlite ORM - PUBLIC DOMAIN LICENSE
 *  Copyright (C)  2010-2012. Ian Quigley
 *  
 *  This source code is provided 'As is'. You bear the risk of using it.
 */

using System;
using SqliteORM.Tests.Model;
using Xunit;
using SubSpec;
using System.Collections.Generic;
using System.Linq;

namespace SqliteORM.Tests
{
	public class Types
	{
		[Specification]
		public void StoreAndRetrieve()
		{
            List<TableTypes> test = new List<TableTypes>()
            {
           //     new TableTypes() { Id = 1, Bool = true, Date = new DateTime(2012,1,3), Decimal = 32.3M, Double = 132324.2376127361, Float = 84723847283.12312312F, Long = 0x4000800010002000, MoreText = "Blah", Text = "Stuff", Time = TimeSpan.FromMinutes(10), Uint16 = 0xFFFF},
                new TableTypes() { Id = 2, Bool = true, Date = new DateTime(1312,4,3), Decimal = 122.3433M, Double = 132323324.2376121373, Float = 0.0123012312312F, Long = 0x40008000FFAAFFAA, MoreText = "hrowiehrowehroiwheroihwe rweoihr woiehr woeihr owiehrowiehr owiehr owiehr ", Text = "Stuff", Time = TimeSpan.FromMinutes(-10), Uint16 = 0},
			//	new TableTypes() { Id = 3, Bool = true, Date = DateTime.MaxValue, Decimal = Decimal.MaxValue, Double = Double.MaxValue, Float = float.MaxValue, Long = long.MaxValue, MoreText = "hrowiehrowehroiwheroihwe rweoihr woiehr woeihr owiehrowiehr owiehr owiehr ", Text = "Stuff", Time = TimeSpan.MaxValue, Uint16 = UInt16.MaxValue },
				//new TableTypes() { Id = 4, Bool = true, Date = DateTime.MinValue, Decimal = Decimal.MinValue, Double = Double.MinValue, Float = float.MinValue, Long = long.MinValue, MoreText = "hrowiehrowehroiwheroihwe rweoihr woiehr woeihr owiehrowiehr owiehr owiehr ", Text = "Stuff", Time = TimeSpan.MinValue, Uint16 = UInt16.MinValue },
            };

            "Given an empty database".Context(
                () =>
                {
                    Context.Initialise();
                    DbConnection.Initialise(Context.ConnectionString);
                });

			"when we create table of type-test data".Do( 
                () => {
                    using (TableAdapter<TableTypes> adapter = TableAdapter<TableTypes>.Open())
			            {
                            foreach (TableTypes type in test)
				                adapter.CreateUpdate( type );
                        }
                });

            "expect that we can retrieve the data".Assert(
                () => {
                    using (TableAdapter<TableTypes> adapter = TableAdapter<TableTypes>.Open())
                        {
                            foreach (TableTypes type in test)
                                Assert.NotNull(adapter.Read(type.Id));
			            } });

            "expect that the data is same as stored".Assert(
                () =>
                {
                    using (TableAdapter<TableTypes> adapter = TableAdapter<TableTypes>.Open())
                    {
                        foreach (TableTypes type in test)
                        {
                            TableTypes result = adapter.Read(type.Id);

                            Assert.True(adapter.AreSame(result, type));

                        }
                    }
                });

		}

		[Specification]
		public void StoreAndRetrieveEnum()
		{
			List<TableEnum> test = new List<TableEnum>()
            {
                new TableEnum() { Enum = MyEnum.CheckOne},
				new TableEnum() { Enum = MyEnum.CheckThree},
				new TableEnum() { Enum = MyEnum.CheckFour},
            };

			"Given an empty database".Context(
				() =>
				{
					Context.Initialise();
					DbConnection.Initialise(Context.ConnectionString);
                    Context.DropTables();
				});

			"when we create table of type-enum data with auto-incremement PK".Do(
				() =>
				{
					using (TableAdapter<TableEnum> adapter = TableAdapter<TableEnum>.Open())
					{
						foreach (TableEnum type in test)
							adapter.CreateUpdate(type);
					}
				});

			"expect that we can retrieve the data".Assert(
				() =>
				{
					using (TableAdapter<TableEnum> adapter = TableAdapter<TableEnum>.Open())
					{
						foreach (TableEnum type in test)
							Assert.NotNull(adapter.Read(type.Id));
					}
				});

            "expect that the data is same as stored".Assert(
                () =>
                {
                    using (TableAdapter<TableEnum> adapter = TableAdapter<TableEnum>.Open())
                    {
                        foreach (TableEnum type in test)
                        {
                            TableEnum result = adapter.Read(type.Id);

                            Assert.True(adapter.AreSame(result, type));

                        }
                    }
                });

            "expect that the primary key values are unique".Assert(
                            () =>
                            {
                                using (TableAdapter<TableEnum> adapter = TableAdapter<TableEnum>.Open())
                                {
                                    var pks = (from t in test select t.Id).Distinct();

                                    Assert.Equal(pks.Count(), test.Count());
                                }
                            });

		}

        [Specification]
        public void UsingAClassInstance()
        {
            "Given an empty database".Context(
                () =>
                {
                    Context.Initialise();
                    DbConnection.Initialise(Context.ConnectionString);
                });

            TableIdString test = new TableIdString() { Id = 23, Text = "Hello" };

            "when we store a class ".Do(
                () =>
                {
                    using (TableAdapter<TableIdString> adapter = TableAdapter<TableIdString>.Open())
                    {
                        adapter.CreateUpdate(test);
                    }
                });

            "expect that we can retrieve the class".Assert(
                () =>
                {
                    using (TableAdapter<TableIdString> adapter = TableAdapter<TableIdString>.Open())
                    {
                        TableIdString result = adapter.Read( test.Id );

                        Assert.NotNull(result);
                        Assert.Equal(test.Id, result.Id);
                        Assert.Equal(test.Text, result.Text);
                    }
                });
        }

        [Specification]
        public void UpdateAClassKnownDataNotChanged()
        {
            TableIdString test = new TableIdString() { Id = 23, Text = "Hello" };
            TableIdString known = new TableIdString() { Id = 19, Text = "Kimple Dog Bah" };

            "Given an table with a row of data".Context(
                () =>
                {
                    Context.Initialise();
                    DbConnection.Initialise(Context.ConnectionString);

                    using (TableAdapter<TableIdString> adapter = TableAdapter<TableIdString>.Open())
                    {
                        adapter.CreateUpdate(test);
                        adapter.CreateUpdate(known);
                    }
                });


            "when we store the updated class".Do(
                () =>
                {
                    using (TableAdapter<TableIdString> adapter = TableAdapter<TableIdString>.Open())
                    {
                        test.Text = "Goodbye";
                        adapter.CreateUpdate(test);
                    }
                });

            "expect the updated data was stored".Assert(
                () =>
                {
                    using (TableAdapter<TableIdString> adapter = TableAdapter<TableIdString>.Open())
                    {
                        TableIdString result = adapter.Read(test.Id);

                        Assert.NotNull(result);
                        Assert.Equal(test.Id, result.Id);
                        Assert.Equal(test.Text, result.Text);
                    }
                });

            "expect that the known data is unchanged".Assert(
                () =>
                {
                    using (TableAdapter<TableIdString> adapter = TableAdapter<TableIdString>.Open())
                    {
                        TableIdString result = adapter.Read(known.Id);

                        Assert.NotNull(result);
                        Assert.Equal(known.Id, result.Id);
                        Assert.Equal(known.Text, result.Text);
                    }
                });

        }

		[Specification]
		public void AdapterAreSameReturnsFalseWithNotEqualData()
		{
			"Without context".Context( ( ) =>
			                           	{
											Context.Initialise();
											DbConnection.Initialise(Context.ConnectionString);
			                           	} );

			bool result = default(bool);

			"when comparing to not-equal classes".Do(
				( ) =>
					{
						using (TableAdapter<TableIdString> adapter = TableAdapter<TableIdString>.Open())
						{
							TableIdString one = new TableIdString {Id = 1, Text = "Hello"};
							TableIdString two = new TableIdString {Id = 1, Text = "HELLO"};

							result = adapter.AreSame( one, two );
						}
					} );

			"expect false result".Assert(
				( ) => Assert.False( result ) );
		}
	}
}
